﻿using System;
using System.Collections.Generic;
using CF.CFLog;

namespace CF.Event
{
    /// <summary>
    /// 事件系统
    /// </summary>
    public static class EventManager
    {
        private static readonly Dictionary<GameEvent, HashSet<Delegate>> Events = new Dictionary<GameEvent, HashSet<Delegate>>();
        
        public static void AddListener(GameEvent gameEvent, Action addListener)
        {
            TryAddListener(gameEvent, addListener);
        }

        public static void AddListener<T1>(GameEvent gameEvent, Action<T1> addListener)
        {
            TryAddListener(gameEvent, addListener);
        }
        
        public static void AddListener<T1, T2>(GameEvent gameEvent, Action<T1, T2> addListener)
        {
            TryAddListener(gameEvent, addListener);
        }
        
        public static void AddListener<T1, T2, T3>(GameEvent gameEvent, Action<T1, T2, T3> addListener)
        {
             TryAddListener(gameEvent, addListener);
        }
        
        public static void AddListener<T1, T2, T3, T4>(GameEvent gameEvent, Action<T1, T2, T3, T4> addListener)
        {
            TryAddListener(gameEvent, addListener);
        }
        
        public static void AddListener<T1, T2, T3, T4, T5>(GameEvent gameEvent, Action<T1, T2, T3, T4, T5> addListener)
        {
            TryAddListener(gameEvent, addListener);
        }

        public static void RemoveListener(GameEvent gameEvent, Action removeListener)
        {
            TryRemoveListener(gameEvent, removeListener);
        }
        
        public static void RemoveListener<T1>(GameEvent gameEvent, Action<T1> removeListener)
        {
            TryRemoveListener(gameEvent, removeListener);
        }
        
        public static void RemoveListener<T1, T2>(GameEvent gameEvent, Action<T1, T2> removeListener)
        {
            TryRemoveListener(gameEvent, removeListener);
        }
        
        public static void RemoveListener<T1, T2, T3>(GameEvent gameEvent, Action<T1, T2, T3> removeListener)
        {
            TryRemoveListener(gameEvent, removeListener);
        }
        
        public static void RemoveListener<T1, T2, T3, T4>(GameEvent gameEvent, Action<T1, T2, T3, T4> removeListener)
        {
            TryRemoveListener(gameEvent, removeListener);
        }
        
        public static void RemoveListener<T1, T2, T3, T4, T5>(GameEvent gameEvent, Action<T1, T2, T3, T4, T5> removeListener)
        {
            TryRemoveListener(gameEvent, removeListener);
        }
        
        public static void SendMessage(GameEvent gameEvent)
        {
            if (Events.TryGetValue(gameEvent, out HashSet<Delegate> hadListener))
            {
                foreach (var dDelegate in hadListener)
                {
                    try
                    {
                        ((Action) dDelegate) ();
                    }
                    catch (Exception e)
                    {
                        Log.Error($"GameEvent {gameEvent} try invoke delegate {dDelegate} failed!. Error message: {e.Message}");
                        throw;
                    }
                }
            }
        }
        
        public static void SendMessage<T1>(GameEvent gameEvent, T1 arg1)
        {
            if (Events.TryGetValue(gameEvent, out HashSet<Delegate> hadListener))
            {
                foreach (var dDelegate in hadListener)
                {
                    try
                    {
                        ((Action<T1>) dDelegate) (arg1);
                    }
                    catch (Exception e)
                    {
                        Log.Error($"GameEvent {gameEvent} try invoke delegate {dDelegate} failed!. Error message: {e.Message}");
                        throw;
                    }
                }
            }
        }
        
        public static void SendMessage<T1, T2>(GameEvent gameEvent, T1 arg1, T2 arg2)
        {
            if (Events.TryGetValue(gameEvent, out HashSet<Delegate> hadListener))
            {
                foreach (var dDelegate in hadListener)
                {
                    try
                    {
                        ((Action<T1, T2>) dDelegate) (arg1, arg2);
                    }
                    catch (Exception e)
                    {
                        Log.Error($"GameEvent {gameEvent} try invoke delegate {dDelegate} failed!. Error message: {e.Message}");
                        throw;
                    }
                }
            }
        }
        
        public static void SendMessage<T1, T2, T3>(GameEvent gameEvent, T1 arg1, T2 arg2, T3 arg3)
        {
            if (Events.TryGetValue(gameEvent, out HashSet<Delegate> hadListener))
            {
                foreach (var dDelegate in hadListener)
                {
                    try
                    {
                        ((Action<T1, T2, T3>) dDelegate) (arg1, arg2, arg3);
                    }
                    catch (Exception e)
                    {
                        Log.Error($"GameEvent {gameEvent} try invoke delegate {dDelegate} failed!. Error message: {e.Message}");
                        throw;
                    }
                }
            }
        }
        
        public static void SendMessage<T1, T2, T3, T4>(GameEvent gameEvent, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
        {
            if (Events.TryGetValue(gameEvent, out HashSet<Delegate> hadListener))
            {
                foreach (var dDelegate in hadListener)
                {
                    try
                    {
                        ((Action<T1, T2, T3, T4>) dDelegate) (arg1, arg2, arg3, arg4);
                    }
                    catch (Exception e)
                    {
                        Log.Error($"GameEvent {gameEvent} try invoke delegate {dDelegate} failed!. Error message: {e.Message}");
                        throw;
                    }
                }
            }
        }
        
        public static void SendMessage<T1, T2, T3, T4, T5>(GameEvent gameEvent, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
        {
            if (Events.TryGetValue(gameEvent, out HashSet<Delegate> hadListener))
            {
                foreach (var dDelegate in hadListener)
                {
                    try
                    {
                        ((Action<T1, T2, T3, T4, T5>) dDelegate) (arg1, arg2, arg3, arg4, arg5);
                    }
                    catch (Exception e)
                    {
                        Log.Error($"GameEvent {gameEvent} try invoke delegate {dDelegate} failed!. Error message: {e.Message}");
                        throw;
                    }
                }
            }
        }
        
        private static void TryAddListener(GameEvent gameEvent, Delegate listener)
        {
            if (Events.TryGetValue(gameEvent, out HashSet<Delegate> hadListener))
            {
                if (!hadListener.Add(listener))
                {
                    Log.Error($"GameEvent {gameEvent} try add same listener {listener} failed!.");
                }
            }
            else
            {
                Events.Add(gameEvent, new HashSet<Delegate> {listener});
            }
        }

        public static void TryRemoveListener(GameEvent gameEvent, Delegate listener)
        {
            if (Events.TryGetValue(gameEvent, out HashSet<Delegate> hadListener))
            {
                if (!hadListener.Remove(listener))
                {
                    Log.Error($"GameEvent {gameEvent} try remove the listener {listener} failed.");
                }
            }
            else
            {
                Log.Error($"GameEvent {gameEvent} did not have any listeners.");
            }
        }

        public static void Clear(GameEvent gameEvent)
        {
            Events.Remove(gameEvent);
        }
        
        public static void ClearAll()
        {
            Events.Clear();
        }
    }
}